/*
 * Event.java
 * 
 * author: The MomberBan Team
 *    date: 12.09.2008
 * 
 * 
 */

package at.momberban.game.me;

/**
 * encapsulates a game event and provides functionality to de-/encode an event
 * from/to a string
 * 
 * @see Event#encode()
 * @see Event#decode()
 * @author patchinsky
 */
public class Event {
    // java byte range is from -128 to 127 (
    // -0x80 to 0x79

    /**
     * start the game
     */
    public static final char GAME_START = 'A';

    /**
     * end the game [p(winner, null if no-one wins)]
     */
    public static final char GAME_END = 'Z';

    /**
     * a player has joined [id,name,challenge]
     */
    public static final char JOIN_EVENT = 'j';

    /**
     * a player leaves [id]
     */
    public static final char LEAVE_EVENT = 'l';

    /**
     * broadcast all player ids [id1,id2,...]
     */
    public static final char PLAYERS_ACTIVE = 'a';

    /**
     * move a player [p,x,y]
     */
    public static final char MOVE_PLAYER = 'm';

    /**
     * bomb has been planted [p,b_id]
     */
    public static final char BOMB_PLANTED = 'b';

    /**
     * bomb(s) exploded [b1, b2, b3]
     */
    public static final char BOMB_EXPLODE = 'e';

    /**
     * player died [p(who),p(by)]
     */
    public static final char PLAYER_DEAD = 'd';

    /**
     * server full event [challenge]
     */
    public static final char SERVER_FULL = 'f';

    /**
     * all player positions [x1,y1,x2,y2,...]
     */
    public static final char PLAYER_POSITIONS = 'P';

    /**
     * all bomb positions [x1,y1,x2,y2,...]
     */
    public static final char BOMB_POSITIONS = 'B';
    
    /**
     * if the client is disconnected from the server
     */
    public static final char NETWORK_DISCONNECTED = '!';

    /**
     * event delimiter
     */
    public static final char DELIMITER = '\t'; // TAB don't change

    /**
     * workaround for integrity
     */
    private static final String DEFAULT_PAYLOAD = "void";

    private static StringBuffer buffer = new StringBuffer();
    
    private static SynchronizedQueue eventQueue = new SynchronizedQueue();

    private char id;
    
    private String[] data;

    private String encoded;
    

    /**
     * constructor
     * 
     * @param eventID
     *            the event id
     * @param payload
     *            the data
     */
    private Event(char eventID, String[] payload, String encoded) {
        this.id = eventID;
        this.data = payload;
        this.encoded = encoded;
    }

    /**
     * @return eventQueue
     */
    public final static SynchronizedQueue getEventQueue() {
        return eventQueue;
    }

    /**
     * return the pay-load
     * 
     * @return
     */
    public final String[] getData() {
        return this.data;
    }

    /**
     * @param data
     *            to set
     */
    public void setData(String[] data) {
        this.data = data;
    }

    /**
     * return the type
     * 
     * @return
     */
    public final char getID() {
        return this.id;
    }
    
    /**
     * @return encoded
     */
    public String getEncoded() {
        return encoded;
    }
    
    /**
     * encode events
     * 
     * @param id
     *            the event id
     * @param data
     *            the data
     * @return encoded event
     */
    public static final synchronized String encode(char id, String[] data) {
        // String[] data = e.getData();
        // byte id = e.getID();

        buffer.setLength(0);
        int length = (data == null) ? 0 : data.length;

        /*
         * format: [length]|[id]|[data0]|[data1]
         */
        buffer.append(length);
        buffer.append(DELIMITER);
        buffer.append(id);

        // add additional data
        if (length > 0) {
            for (int i = 0; i < length; i++) {
                buffer.append(DELIMITER);
                buffer.append(data[i]);
            }
        } else {
            buffer.append(DELIMITER);
            buffer.append(DEFAULT_PAYLOAD);
        }

        buffer.append("\n");

        return buffer.toString();
    }

    /**
     * decode an event from the network into a new event instance. a valid event
     * has at minimum three chars. (length, delimiter, eventId)
     * 
     * @param encoded
     * @return
     */
    public static final Event decode(String encoded) {
        Event ret = null;

        if (encoded.length() >= 3) {
            // the data length
            int length = StringUtilities.getNumericValue(encoded.charAt(0));
            char eventId = encoded.charAt(2);

            String[] payload = null;
            if (length > 0) {
                payload = StringUtilities.tokenize(encoded.substring(4, encoded
                        .length() - 1), DELIMITER);
                
                if (length != payload.length) {
                    Logger.log("event: invalid event string length: expexted: "
                            + length + " was: " + payload.length);
                    Logger.log("event: payload: " + encoded.substring(4));
                }
            }

            ret = new Event(eventId, payload, encoded);
        } else {
            Logger.log("invalid length (" + encoded.length() + ") " + encoded);
        }

        return ret;
    }

}
